<?php

namespace App\Http\Middleware\Api;

use App\Exceptions\ResponseException;
use Closure;
use Illuminate\Support\Facades\Auth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Illuminate\Auth\AuthenticationException;

class JwtTokenCheck extends BaseMiddleware
{
	protected $newToken = ''; //新token

	/**
	 * jwt token检查中间件，每次请求的时候，都检查一次是否过期。
	 *
	 * @param  \Illuminate\Http\Request $request
	 * @param  \Closure $next
	 * @return mixed
	 */
	public function handle($request, Closure $next)
	{
//        app()->instance(\Illuminate\Contracts\Auth\Guard::class, auth('api'));
		//如果有，就要判断是否能正确解析出用户信息，解析过程中，可能存在token过期的情况，那么会抛出异常
		try {

//			$auth = ;
			//如果没有授权凭证  踩坑记录: 一定要指定guard 不然 jwt会默认使用Laravel默认的guard 当前后端不同的guard时，报错
//			if ( ! $token = auth('api')->getToken()) {
//			if ( ! $token = JWTAuth::parseToken()->getToken()) {
//				throw new ResponseException(401, '您尚未登录，请先登录后再操作');
//			}
//
//			//验证载荷信息
//            $user = JWTAuth::parseToken()->authenticate();
//			if ( ! $user) {
//				throw new ResponseException(401, '用户信息查询失败，请重新登录');
//			}
            $authToken = Auth::guard('api')->getToken();
            if(!$authToken){
                return response(['code'=>401,'msg'=>'您尚未登录，请先登录后再操作'],200);
            }

            //如果已經失去登錄狀態了，就手动抛出异常
            if(!auth('api')->check()){
//                $this->newToken = auth('api')->refresh();
                throw new TokenExpiredException('token_expired');
            }

            //判断用户状态
            if(auth('api')->user()->status != 1){
                return response(['code'=>401,'msg'=>'登录状态失效，请重新登录'],200);
            }

		} catch (TokenExpiredException $exception) {
            //过期，分2种情况，一种是token过期，刷新token未过期 刷新token时间设定为14天
            try {
//				$this->newToken = JWTAuth::refresh($token);
                $this->newToken = auth('api')->refresh();

                \Log::info('從下面刷新了-----------');

                //一次性登录，保证本次请求有效
                \Auth::guard('api')->onceUsingId(auth('api')->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']);

                $request->headers->set('Authorization', 'Bearer ' . $this->newToken);
            } catch (JWTException $JWTException) {
                \Log::info('无法再刷新了、' . $JWTException->getMessage());
                //到了这一步，表示已经无法刷新了，必须退出登录
                throw new ResponseException(401, '登录已过期，请重新登录');
            }

        }catch (AuthenticationException $exception){

		    \Log::info('這裡是過期了 保存時間過期。');
            throw new ResponseException(401, '登录身份保存时长已过期，请重新登录');

		} catch (JWTException $JWTException) {

            \Log::info('异常1：、' . $JWTException->getMessage());
			throw new ResponseException(401, '登录身份异常或已过期，请重新登录');

		} catch (TokenInvalidException $tokenInvalidException) {

			//令牌验证错误 比如无法从请求中解析令牌
            \Log::info('异常2、' . $tokenInvalidException->getMessage());
			throw new ResponseException(401, '用户信息查询异常，请重新登录');
		}

		$response = $next($request);
		//如果有新token，放入到头部返回给前端
		if ($this->newToken) {
			$response->headers->set('Authorization', 'Bearer ' . $this->newToken);
		}

		return $response;
	}

	//	如何将新的token发给前端比较好？
	//  这个问题答案简单，在response 的header中设置authorization。
	//   关键点：后端一般使用的域名是二级域名比如我的是api.xx.com,会和前端产生一个跨域的影响，请记得一定要设置
	//   `$response->headers->set('Access-Control-Expose-Headers', 'Authorization');`
	//   设置跨域的时候还要设置一个Cache-Control,这个东西出现的问题真的是莫名其妙，坑了我很久..
	//   `$response->headers->set('Cache-Control', 'no-store'); // 无的话会导致前端从缓存获取头token`
}
